/**
 @file ctc_usw_nexthop_fp_cli.c

 @date 2020-08-07

 @version v2.0

 The file apply clis of port module
*/

#include "ctc_api.h"
#include "ctcs_api.h"
#include "sal.h"
#include "ctc_cli.h"
#include "ctc_cli_common.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "ctc_nexthop_cli.h"

/*Move flex edit API to sys layer*/
/**
 @brief  Define flexible programing edit type {ins/del/rep}
*/
#if 0
enum ctc_nh_fp_edit_type_e
{
   CTC_NH_FP_EDIT_INS,   /**< [TMM] do insert edit*/
   CTC_NH_FP_EDIT_DEL,   /**< [TMM] do delete edit*/
   CTC_NH_FP_EDIT_REP    /**< [TMM] do replace edit*/
};
typedef enum ctc_nh_fp_edit_type_e ctc_nh_fp_edit_type_t;

/**
 @brief  Define flexible programing data type
*/
enum ctc_nh_fp_data_type_e
{
   CTC_NH_FP_DATA_RAW,               /**< [TMM] raw data, for use define data*/
   CTC_NH_FP_DATA_PACKET,            /**< [TMM] data extract from in packet*/
   CTC_NH_FP_DATA_SRC_PORT,          /**< [TMM] use source global port*/
   CTC_NH_FP_DATA_DST_PORT,          /**< [TMM] use dest global port*/
   CTC_NH_FP_DATA_SRC_LPORT,         /**< [TMM] use source local port*/
   CTC_NH_FP_DATA_DST_LPORT,         /**< [TMM] use dest local port*/
   CTC_NH_FP_DATA_HASH_VALUE,        /**< [TMM] use hash value*/
   CTC_NH_FP_DATA_QUEUE_ID,          /**< [TMM] use queue id*/
   CTC_NH_FP_DATA_L3_PROTOCOL,       /**< [TMM] use l3 header protocol*/
   CTC_NH_FP_DATA_SRC_VLAN_PTR,      /**< [TMM] use source vlan ptr*/
   CTC_NH_FP_DATA_L3_INTF,           /**< [TMM] use dest l3 interface id*/
   CTC_NH_FP_DATA_LOGIC_SRC_PORT,    /**< [TMM] use logic source port*/
   CTC_NH_FP_DATA_LOGIC_DST_PORT,    /**< [TMM] use logic dest port*/
   CTC_NH_FP_DATA_QUEUE_DEPTH,       /**< [TMM] use queue depth*/
   CTC_NH_FP_DATA_SPAN_ID,           /**< [TMM] use span id*/
   CTC_NH_FP_DATA_FLEX_LEN,          /**< [TMM] flex length from ingress scl*/
   CTC_NH_FP_DATA_TTL,               /**< [TMM] use packet ttl*/
   CTC_NH_FP_DATA_IP_LEN,            /**< [TMM] use packet ip length*/
   CTC_NH_FP_DATA_LOAD_METRIC,       /**< [TMM] use Load metric*/
   CTC_NH_FP_DATA_LATENCY,           /**< [TMM] use packet latency*/
   CTC_NH_FP_DATA_TS_HIGH,           /**< [TMM] use timestamp high bits*/
   CTC_NH_FP_DATA_TS_LOW,            /**< [TMM] use timestamp low bits*/
   CTC_NH_FP_DATA_IGS_TS,            /**< [TMM] use ingress timestamp*/
   CTC_NH_FP_DATA_EGS_TS,            /**< [TMM] use egress timestamp*/
   CTC_NH_FP_DATA_IGS_TS_HIGH,       /**< [TMM] use ingress timestamp high*/
   CTC_NH_FP_DATA_IGS_TS_LOW,         /**< [TMM] use ingress timestamp low*/
   CTC_NH_FP_DATA_FLEX_POS
};
typedef enum ctc_nh_fp_data_type_e ctc_nh_fp_data_type_t;

/**
 @brief  Define flexible programing zone
*/
enum ctc_nh_fp_zone_e
{
   CTC_NH_FP_ZONE_PACKET,      /**< [TMM] fp operate on packet zone*/
   CTC_NH_FP_ZONE_INS_DATA     /**< [TMM] fp operate on insert data zone*/
};
typedef enum ctc_nh_fp_zone_e ctc_nh_fp_zone_t;

/**
 @brief  Define flexible programing operator
*/
enum ctc_nh_fp_op_e
{
   CTC_NH_FP_OP_NOP,    /**< [TMM] do no opreator*/
   CTC_NH_FP_OP_GT,     /**< [TMM] operator >*/
   CTC_NH_FP_OP_GE,     /**< [TMM] operator >=*/
   CTC_NH_FP_OP_LT,     /**< [TMM] operator <*/
   CTC_NH_FP_OP_LE,     /**< [TMM] operator <=*/
   CTC_NH_FP_OP_EQ,     /**< [TMM] operator =*/
   CTC_NH_FP_OP_NE,     /**< [TMM] operator !=*/
   CTC_NH_FP_OP_ADD,    /**< [TMM] operator +*/
   CTC_NH_FP_OP_SUB,    /**< [TMM] operator -*/
   CTC_NH_FP_OP_SHL,    /**< [TMM] operator <<*/
   CTC_NH_FP_OP_SHR,    /**< [TMM] operator >>*/
   CTC_NH_FP_OP_ROL,    /**< [TMM] operator <<(ROL)*/
   CTC_NH_FP_OP_ROR     /**< [TMM] operator >>(ROR)*/
};
typedef enum ctc_nh_fp_op_e ctc_nh_fp_op_t;

/**
 @brief  Define flexible programing field data
*/
struct ctc_nh_fp_data_s
{
    uint8 type;       /**< [TMM] data type, refer to ctc_nh_fp_data_type_t*/
    uint8 len;        /**< [TMM] operator data length, Uints:bits*/
    uint8 shift;      /**< [TMM] operator data shift (data left shift bits), Uints: bits*/
    uint8 rsv;
    uint32 mask;      /**< [TMM] operator data mask, Uints: bits*/
    uint32 value;     /**< [TMM] value when data type use CTC_NH_FP_DATA_RAW*/
    uint8 id;         /**< [AT] 0~3, means select form 4bits, 8bits, 16bits or 32bits container*/
    uint8 sel;        /**< [AT] */
};
typedef struct ctc_nh_fp_data_s ctc_nh_fp_data_t;

/**
 @brief  Define flexible programing field check condition
*/
struct ctc_nh_fp_field_chk_s
{
    uint8 chk_op;     /**< [TMM] check oprerator, refore to ctc_nh_fp_op_t, only support CTC_NH_FP_OP_GT/LT/EQ/NE/GE/LE**/
    uint8 discard;    /**< [TMM] check opeartion and discard the packet*/
    uint8 to_cpu;     /**< [TMM] check opeartion copy or redirect to cpu*/
    uint8 rsv;

};
typedef struct ctc_nh_fp_field_chk_s ctc_nh_fp_field_chk_t;

/**
 @brief  Define flexible programing field
*/
struct ctc_nh_fp_field_s
{
    uint16 offset;            /**< [TMM] edit zone field offset, Unit: bits*/
    uint8 len;                /**< [TMM] edit zone field length, max is 32bits, Unit:bits*/
    uint8 zone;               /**< [TMM] edit zone, refer to ctc_nh_fp_zone_t*/
    uint8 data_op;            /**< [TMM] data operator, data (oprerator +/-) data_r, refer to ctc_nh_fp_op_t*/
    uint8 zone_op;            /**< [TMM] zone operator,(oprerator +/-) with packet or ins data, refer to ctc_nh_fp_op_t*/
    uint8 result_shift;       /**< [TMM] data operator result shift (shift right), Uint:bits*/
    uint8 rsv;
    ctc_nh_fp_data_t data;    /**< [TMM] field data, if use alu, use as data_operator left value*/
    ctc_nh_fp_data_t data_r;  /**< [TMM] field data which use as data_operator right value*/
    ctc_nh_fp_field_chk_t chk;     /**< [TMM] data operator check which packet will be drop or to cpu*/
};
typedef struct ctc_nh_fp_field_s ctc_nh_fp_field_t;


/**
 @brief  Define flexible programing chksum field
*/
struct ctc_nh_fp_chksum_s
{
    uint8 enable;            /**< [TMM] update checksum enable*/
    uint8 offset;            /**< [TMM] checksum offset from l3 or l4, if offset == 0xFF, offset will auto cal, uint:Bytes*/
    uint8 extra_update;      /**< [TMM] insert/del header update enable*/
    uint8 rsv;
    uint32 mask;            /**< [TMM] mask bitmap which 1 bit be regard as 4bit packet length*/
};
typedef struct ctc_nh_fp_chksum_s ctc_nh_fp_chksum_t;


#define CTC_NH_FP_FIELD_MAX 16
enum ctc_nh_fp_flag_e
{
   CTC_NH_FP_FLAG_XPF           = 0x00000001,    /**< [AT] xfp, use xedit*/
   CTC_NH_FP_FLAG_L3_LEN_UPDATE = 0x00000002,    /**< [AT] L3 len update*/
   CTC_NH_FP_FLAG_L4_LEN_UPDATE = 0x00000004,    /**< [AT] L4 len update*/
   CTC_NH_FP_FLAG_WITHOUT_TMP   = 0x00000008,    /**< [AT] If set, not use DsFlexEditInsertHeaderTemplate for CTC_NH_FP_EDIT_INS*/
   CTC_NH_FP_FLAG_RW_SEL_VALID  = 0x00000010     /**< [AT] If set, set rewriteOpSegmentSel for CTC_NH_FP_EDIT_INS*/
};
typedef enum ctc_nh_fp_flag_e ctc_nh_fp_flag_t;

/**
 @brief  Define flexible programing edit structure
*/
struct ctc_nh_fp_edit_s
{
    uint32 fp_id;             /**< [TMM]  fp id, if set 0, return id by SDK*/
    uint32 flag;
    uint8 edit_type;          /**< [TMM] edit type, refer to ctc_nh_fp_edit_type_t*/
    uint8 offset_type;        /**< [TMM] edit offset type, refer to ctc_pkt_offset_type_t*/
    uint8 offset;             /**< [TMM] edit offset from offset_type, uint:Bytes*/
    uint8 len;                /**< [TMM] edit length which use for insert or delete, unit: Bytes */
    uint8 offset_type_ext;    /**< [TMM] edit offset type, for extra packet modify*/
    uint8 offset_ext;         /**< [TMM] edit offset for extra packet modify from offset_type_ext, uint:Bytes*/
    uint8 ext_is_outer;       /**< [AT]  if set, mean edit outer pakcet when encap*/
    uint8 *data;              /**< [TMM] raw data which use for insert*/
    uint8 field_cnt;          /**< [TMM] field list cnt*/
    ctc_nh_fp_field_t* p_field_list; /**< [TMM] operate field array*/
    uint8 len_from_data;        /**< [TMM] if set, insert or del length from ctc_nh_fp_data_t*/
    ctc_nh_fp_data_t length;    /**< [TMM] insert or del length from ctc_nh_fp_data_t*/
    ctc_nh_fp_chksum_t l3chksum; /**< [TMM] layer3 checksum update*/
    ctc_nh_fp_chksum_t l4chksum; /**< [TMM] layer4 checksum update*/
    uint32 next_fp_id;         /**< [AT] xfp id*/
    uint8 rw_sel;              /**< [AT] set rewriteOpSegmentSel for CTC_NH_FP_EDIT_INS*/
};
typedef struct ctc_nh_fp_edit_s ctc_nh_fp_edit_t;


/**
 @brief  Define flexible program edit flags
*/
enum ctc_misc_nh_fp_flag_e
{
    CTC_MISC_NH_FP_FLAG_OP_BRIDGE = 0x0001, /**< [MM] Flex program do bridge opreation */
};
typedef enum ctc_misc_nh_fp_flag_e ctc_misc_nh_fp_flag_t;
/**
 @brief  Define flexible program edit parameter structure
*/
struct ctc_misc_nh_fp_edit_param_s
{
    uint32 fp_id;    /**< [TMM] nexthop flex program  id */
    uint16 span_id;  /**< [TMM] span id which used for fp edit */
    uint16 flag;     /**< [TMM] flex program flag, refer to ctc_misc_nh_fp_flag_t */
};
typedef struct ctc_misc_nh_fp_edit_param_s ctc_misc_nh_fp_edit_param_t;

extern int32
sys_usw_nh_add_fp(uint8 lchip, ctc_nh_fp_edit_t* p_edit, uint8 is_internal);

extern int32
sys_usw_nh_update_fp(uint8 lchip, ctc_nh_fp_edit_t* p_edit);

extern int32
sys_usw_nh_remove_fp(uint8 lchip, uint32 fp_id);
#endif

#define CTC_CLI_FP_FIELD_TYPE_STR "(raw DATA|packet|src-port|dst-port|src-lport|dst-lport|\
                                   hash-value|queue-id|l3-proto|src-vlan-ptr|l3if-id|logic-src-port|\
                                   logic-dst-port|queue-depth|span-id|flex-len|ttl|ip-len|load-metric|\
                                   latency|ts-high|ts-low|igs-ts|egs-ts|igsts-high|igsts-low|flex-pos POS OFFSET|es-label|\
                                   fid|vni-id|src-cid|l4-src-port-low|l4-src-port-high|l4-dst-port-low|l4-dst-port-high|pri-color|l3-type|xdata src-offset OFFSET|)"

#define CTC_CLI_FP_FIELD_TYPE_DESC  \
       "raw",\
       "data",\
       "from packet parser result",\
       "source port",\
       "dest port",\
       "source local port",\
       "dest local port",\
       "hash value",\
       "queue id",\
       "layer3 protocol",\
       "source vlan ptr",\
       "dest l3 inteface id",\
       "logic source port",\
       "ligic dest port",\
       "queue depth",\
       "span id",\
       "flex length",\
       "ttl",\
       "ip length",\
       "load metric",\
       "latency",\
       "timestamp high",\
       "timestamp low",\
       "ingress timestamp",\
       "egres timestamp",\
       "ingress timestamp high",\
       "ingress timestamp low",\
       "flex pos",\
       "pos value",\
       "offset",\
       "es label",\
       "Fid",\
       "Vni-id",\
       "Src-cid",\
       "L4-src-port-low",\
       "L4-src-port-high",\
       "L4-dst-port-low",\
       "L4-dst-port-high",\
       "Pri-color",\
       "L3-type",\
       "XDATA",\
       "src-offset",\
       "Offset"


#define _ctc_cli_fp_field       ((ctc_nh_fp_field_t*)CTC_VTY_CLIENT(vty)->nh_fp_field)
#define _ctc_cli_fp_field_cnt   (CTC_VTY_CLIENT(vty)->nh_fp_field_cnt)

extern int32
_ctc_nexthop_cli_alloc_dsnh_offset(ctc_vti_t* vty, uint8 alloc_dsnh_gchip,uint8 nh_type, void* nh_param);

STATIC int32
_ctc_cli_nh_fp_field_init(ctc_vti_t* vty)
{
    if (!CTC_VTY_CLIENT(vty)->nh_fp_field)
    {
        CTC_VTY_CLIENT(vty)->nh_fp_field = mem_malloc(MEM_CLI_MODULE, sizeof(ctc_nh_fp_field_t)*CTC_NH_FP_FIELD_MAX);
        if (!CTC_VTY_CLIENT(vty)->nh_fp_field)  { return CLI_ERROR; }
        sal_memset(CTC_VTY_CLIENT(vty)->nh_fp_field, 0, sizeof(ctc_nh_fp_field_t)*CTC_NH_FP_FIELD_MAX);
    }
    return CLI_SUCCESS;
}

int32 ctc_cli_nh_get_fp_field_data(ctc_vti_t* vty, char** argv, uint8 argc, uint8 index, ctc_nh_fp_data_t* p_data)
{
    uint8 value_exsit = 0;
    uint8 pos_exsit = 0;
    uint8 src_offset_exist = 0;
    uint8 idx = 0;

    if (CTC_CLI_STR_EQUAL_ENHANCE("raw", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_RAW;
        CTC_CLI_GET_UINT32("value", p_data->value, argv[index + 2]);
        value_exsit = 1;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("packet", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_PACKET;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("src-port", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_SRC_PORT;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("dst-port", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_DST_PORT;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("src-lport", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_SRC_LPORT;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("dst-lport", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_DST_LPORT;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("hash-value", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_HASH_VALUE;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("queue-id", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_QUEUE_ID;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l3-proto", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_L3_PROTOCOL;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("src-vlan-ptr", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_SRC_VLAN_PTR;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l3if-id", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_L3_INTF;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("logic-src-port", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_LOGIC_SRC_PORT;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("logic-dst-port", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_LOGIC_DST_PORT;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("queue-depth", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_QUEUE_DEPTH;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("span-id", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_SPAN_ID;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("flex-len", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_FLEX_LEN;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("ttl", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_TTL;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("ip-len", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_IP_LEN;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("load-metric", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_LOAD_METRIC;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("latency", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_LATENCY;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("ts-high", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_TS_HIGH;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("ts-low", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_TS_LOW;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("igs-ts", index+1))
    {
        p_data->type = CTC_NH_FP_DATA_IGS_TS;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("egs-ts", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_EGS_TS;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("igsts-high", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_IGS_TS_HIGH;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("igsts-low", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_IGS_TS_LOW;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("fid", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_FID;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("vni-id", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_VNI_ID;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("src-cid", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_SRC_CID;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l4-src-port-low", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_L4_SRC_PORT_LOW;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l4-src-port-high", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_L4_SRC_PORT_HIGH;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l4-dst-port-low", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_L4_DST_PORT_LOW;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l4-dst-port-high", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_L4_DST_PORT_HIGH;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("pri-color", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_PRI_COLOR;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("l3-type", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_l3_TYPE;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("es-label", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_ESLB;
    }
    else if (CTC_CLI_STR_EQUAL_ENHANCE("xdata", index + 1))
    {
        p_data->type = CTC_NH_FP_DATA_XDATA;
        CTC_CLI_GET_UINT8("xdata src offset", p_data->src_offset, argv[index + 3]);
        src_offset_exist = 1;
    }


    if (pos_exsit)
    {
        CTC_CLI_GET_UINT8("length", p_data->len, argv[index + 4]);
    }
    else if (value_exsit)
    {
        CTC_CLI_GET_UINT8("length", p_data->len, argv[index + 3]);
    }
    else if(src_offset_exist)
    {
        CTC_CLI_GET_UINT8("length", p_data->len, argv[index + 4]);
    }
    else
    {
        CTC_CLI_GET_UINT8("length", p_data->len, argv[index + 2]);
    }

    idx = CTC_CLI_GET_SPECIFIC_INDEX("shift", index);
    if (0xFF != idx && idx <= 6)
    {
        CTC_CLI_GET_UINT8("shift", p_data->shift, argv[index + idx + 1]);
    }

    idx = CTC_CLI_GET_SPECIFIC_INDEX("mask", index);
    if (0xFF != idx &&  idx <= 6)
    {
        CTC_CLI_GET_UINT32("mask", p_data->mask, argv[index + idx + 1]);
    }

    return 0;
}

CTC_CLI(ctc_cli_usw_nh_add_fp_field,
        ctc_cli_usw_nh_add_fp_field_cmd,
        "nexthop fp add field (offset OFFSET) (len LEN) (data "CTC_CLI_FP_FIELD_TYPE_STR" LEN {shift SHIFT| mask MASK|})\
        ( {data-op (gt|ge|lt|le|eq|add|sub|shl|shr|rol|ror) | chk-op (gt|lt|ge|le|eq|ne)} (data-r "CTC_CLI_FP_FIELD_TYPE_STR" LEN {shift SHIFT| mask MASK|}) \
        {discard|to-cpu|} |)\
        {result-shift SHIFT | zone-op (add|sub) | op-zone-data| }",
        CTC_CLI_NH_M_STR,
        "fp",
        "add",
        "field",
        "offset",
        "offset value",
        "length",
        "length value",
        "data",
        CTC_CLI_FP_FIELD_TYPE_DESC,
        "data length",
        "shift",
        "shift left bits",
        "mask",
        "mask bits",
        "data opeartor",
        "greater than >",
        "greater equal than >=",
        "less than <",
        "less eqaul than <=",
        "equal =",
        "add +",
        "sub -",
        "shift left <<",
        "shirt right >>",
        "rol <<",
        "ror >>",
        "check opeartor",
        "greater than >",
        "less than <",
        "greater equal than >=",
        "less equal than <=",
        "equal =",
        "not equal !=",
        "data right",
        CTC_CLI_FP_FIELD_TYPE_DESC,
        "data length",
        "shift",
        "shift left bits",
        "mask",
        "mask bits",
        "discard",
        "copy or redirect to cpu",
        "result shift",
        "result shift bits",
        "zone operation",
        "add +",
        "sub -",
        "operator on insert data zone")
{
    int32 ret = CLI_SUCCESS;
    uint8 index = 0;
    ctc_nh_fp_field_t fp_field;
    sal_memset(&fp_field, 0, sizeof(fp_field));
    ret = _ctc_cli_nh_fp_field_init(vty);
    if (ret == CLI_ERROR)
    {
        ctc_cli_out("%% %s \n", " No memory \n");
        return CTC_E_NO_MEMORY;
    }
    index = CTC_CLI_GET_ARGC_INDEX("offset");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT16("offset", fp_field.offset, argv[index + 1]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("len");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT16("len", fp_field.len, argv[index + 1]);
    }

    index = CTC_CLI_GET_SPECIFIC_INDEX("data", 0);
    if (0xFF != index)
    {
        ctc_cli_nh_get_fp_field_data(vty, argv, argc, index, &fp_field.data);
    }

    index = CTC_CLI_GET_ARGC_INDEX("data-op");
    if (0xFF != index)
    {
        if (CTC_CLI_STR_EQUAL_ENHANCE("gt", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_GT;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("ge", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_GE;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("lt", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_LT;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("le", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_LE;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("eq", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_EQ;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("add", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_ADD;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("sub", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_SUB;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("shl", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_SHL;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("shr", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_SHR;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("rol", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_ROL;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("ror", index + 1))
        {
            fp_field.data_op = CTC_NH_FP_OP_ROR;
        }
    }

    index = CTC_CLI_GET_ARGC_INDEX("chk-op");
    if (0xFF != index)
    {
        if (CTC_CLI_STR_EQUAL_ENHANCE("gt", index + 1))
        {
            fp_field.chk.chk_op= CTC_NH_FP_OP_GT;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("lt", index + 1))
        {
            fp_field.chk.chk_op = CTC_NH_FP_OP_LT;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("ge", index + 1))
        {
            fp_field.chk.chk_op = CTC_NH_FP_OP_GE;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("le", index + 1))
        {
            fp_field.chk.chk_op = CTC_NH_FP_OP_LE;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("eq", index + 1))
        {
            fp_field.chk.chk_op = CTC_NH_FP_OP_EQ;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("ne", index + 1))
        {
            fp_field.chk.chk_op = CTC_NH_FP_OP_NE;
        }
    }

    index = CTC_CLI_GET_SPECIFIC_INDEX("data-r", 0);
    if (0xFF != index)
    {
        ctc_cli_nh_get_fp_field_data(vty, argv, argc, index, &fp_field.data_r);
    }


    index = CTC_CLI_GET_ARGC_INDEX("discard");
    if (0xFF != index)
    {
        fp_field.chk.discard = 1;
    }

    index = CTC_CLI_GET_ARGC_INDEX("to-cpu");
    if (0xFF != index)
    {
        fp_field.chk.to_cpu = 1;
    }

    index = CTC_CLI_GET_ARGC_INDEX("result-shift");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT8("result-shift", fp_field.result_shift, argv[index + 1]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("zone-op");
    if (0xFF != index)
    {
        if (CTC_CLI_STR_EQUAL_ENHANCE("add", index + 1))
        {
            fp_field.zone_op= CTC_NH_FP_OP_ADD;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("sub", index + 1))
        {
            fp_field.zone_op = CTC_NH_FP_OP_SUB;
        }
    }

    index = CTC_CLI_GET_ARGC_INDEX("op-zone-data");
    if (0xFF != index)
    {
        fp_field.zone = CTC_NH_FP_ZONE_INS_DATA;
    }

    if (_ctc_cli_fp_field_cnt >= CTC_NH_FP_FIELD_MAX)
    {
        ctc_cli_out("Invalid fp field cnt!\n");
        return CLI_ERROR;
    }

    sal_memcpy(&_ctc_cli_fp_field[_ctc_cli_fp_field_cnt++], &fp_field, sizeof(fp_field));

    return ret;
}

CTC_CLI(ctc_cli_usw_nh_add_fp_edit,
        ctc_cli_usw_nh_add_fp_edit_cmd,
        "nexthop (add|update) fp (fp-id ID) (insert|delete|replace) (use-outer |) \
        (offset (layer2|layer3|layer4) OFFSET) (len-from-data (flex-len | type VALUE) {op-len VALUE | op-shift VALUE | raw-data VALUE | mask VALUE |}|) \
        {length LEN| data DATA| offset-ext (layer2|layer3|layer4) OFFSET| ext-use-outer|} \
        {l3chsum-update OFFSET BITMAP (l3chsum-extra-en|)|l4chsum-update OFFSET BITMAP (l4chsum-extra-en|) | is-stage2 | keep-l3-len | keep-l4-len |without-template |rep-sel SEL|next-fp-id FPID|}",
        CTC_CLI_NH_M_STR,
        "add",
        "update",
        "fp",
        "fp-id",
        "FP id value, if 0, return id by SDK",
        "insert",
        "delete",
        "replace",
        "offset based on outer head",
        "offset",
        "from layer2",
        "from layer3",
        "from layer4",
        "offset value",
        "length from data",
        "flex len",
        "type : ctc_nh_fp_data_type_t",
        "VALUE",
        "operator data length",
        "VALUE",
        "operator data shift",
        "VALUE",
        "operator data mask",
        "VALUE",
        "raw data",
        "VALUE",
        "insert/delete length",
        "LENGTH VALUE (MUST 2*)",
        "insert data",
        "data value",
        "offset for update packet",
        "from layer2",
        "from layer3",
        "from layer4",
        "offset value",
        "edit outer packet",
        "l3chksum update en",
        "offset value",
        "mask bitmap",
        "include ins/del packet",
        "l4chksum update en",
        "offset value",
        "mask bitmap",
        "include ins/del packet",
        "is stage2 fp",
        "keep-l3-len",
        "keep-l4-len",
        "Without template for insert operation",
        "Replace data sel",
        "Repalce data sel value",
        "Next fp id",
        "Next fp id value"
        )
{

    int32 ret = CLI_SUCCESS;
    uint8 index = 0;
    uint32 fp_id = 0;
    ctc_nh_fp_edit_t fp_edit;
    uint8* data = NULL;

    sal_memset(&fp_edit, 0, sizeof(fp_edit));
    ret = _ctc_cli_nh_fp_field_init(vty);
    if (ret == CLI_ERROR)
    {
        ctc_cli_out("%% %s \n", " No memory \n");
        return CTC_E_NO_MEMORY;
    }
    index = CTC_CLI_GET_ARGC_INDEX("fp-id");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT32("fp-id", fp_edit.fp_id, argv[index + 1]);
        fp_id = fp_edit.fp_id;
    }

    index = CTC_CLI_GET_ARGC_INDEX("insert");
    if (0xFF != index)
    {
        fp_edit.edit_type = CTC_NH_FP_EDIT_INS;
    }

    index = CTC_CLI_GET_ARGC_INDEX("delete");
    if (0xFF != index)
    {
        fp_edit.edit_type = CTC_NH_FP_EDIT_DEL;
    }

    index = CTC_CLI_GET_ARGC_INDEX("replace");
    if (0xFF != index)
    {
        fp_edit.edit_type = CTC_NH_FP_EDIT_REP;
    }

    index = CTC_CLI_GET_ARGC_INDEX("use-outer");
    if (0xFF != index)
    {
        fp_edit.use_outer = 1;
    }

    index = CTC_CLI_GET_ARGC_INDEX("offset");
    if (0xFF != index)
    {
        if (CTC_CLI_STR_EQUAL_ENHANCE("layer2", index + 1))
        {
            fp_edit.offset_type = CTC_PKT_OFFSET_L2;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("layer3", index + 1))
        {
            fp_edit.offset_type = CTC_PKT_OFFSET_L3;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("layer4", index + 1))
        {
            fp_edit.offset_type = CTC_PKT_OFFSET_L4;
        }

        CTC_CLI_GET_UINT16("offset", fp_edit.offset, argv[index + 2]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("len-from-data");
    if (0xFF != index)
    {
    	fp_edit.len_from_data = 1;
		index = CTC_CLI_GET_ARGC_INDEX("flex-len");
		if (0xFF != index)
        {
			fp_edit.length.type = CTC_NH_FP_DATA_FLEX_LEN;
        }
		else
		{
			index = CTC_CLI_GET_ARGC_INDEX("type");
			CTC_CLI_GET_UINT8("type", fp_edit.length.type, argv[index + 1]);
		}
		index = CTC_CLI_GET_ARGC_INDEX("op-len");
		if (0xFF != index)
        {
            CTC_CLI_GET_UINT8("op-len", fp_edit.length.len, argv[index + 1]);
        }
		index = CTC_CLI_GET_ARGC_INDEX("op-shift");
		if (0xFF != index)
		{
			CTC_CLI_GET_UINT8("op-shift", fp_edit.length.shift, argv[index + 1]);
		}
		index = CTC_CLI_GET_ARGC_INDEX("raw-data");
		if (0xFF != index)
		{
			CTC_CLI_GET_UINT32("raw-data", fp_edit.length.value, argv[index + 1]);
		}
		index = CTC_CLI_GET_ARGC_INDEX("mask");
		if (0xFF != index)
		{
			CTC_CLI_GET_UINT32("mask", fp_edit.length.mask, argv[index + 1]);
		}
    }


    index = CTC_CLI_GET_ARGC_INDEX("length");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT16("length", fp_edit.len, argv[index + 1]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("data");
    if (0xFF != index)
    {
        data = mem_malloc(MEM_CLI_MODULE, 16*4);
	  if (!data)
        {
            ctc_cli_out("%% %s \n", "System error: no memory");
            return CLI_ERROR;
        }
        sal_memset(data, 0, 16*4);
        CTC_CLI_GET_STR_UINT8("data", data, argv[index + 1]);
        fp_edit.data = (uint8*)data;
    }

    index = CTC_CLI_GET_ARGC_INDEX("offset-ext");
    if (0xFF != index)
    {
        if (CTC_CLI_STR_EQUAL_ENHANCE("layer2", index + 1))
        {
            fp_edit.offset_type_ext = CTC_PKT_OFFSET_L2;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("layer3", index + 1))
        {
            fp_edit.offset_type_ext = CTC_PKT_OFFSET_L3;
        }
        else if (CTC_CLI_STR_EQUAL_ENHANCE("layer4", index + 1))
        {
            fp_edit.offset_type_ext = CTC_PKT_OFFSET_L4;
        }

        CTC_CLI_GET_UINT16("offset", fp_edit.offset_ext, argv[index + 2]);

        index = CTC_CLI_GET_ARGC_INDEX("ext-use-outer");
        if (0xFF != index)
        {
            fp_edit.ext_use_outer = 1;
        }
    }

    index = CTC_CLI_GET_ARGC_INDEX("l3chsum-update");
    if (0xFF != index)
    {
        fp_edit.l3chksum.enable = 1;
        CTC_CLI_GET_UINT8("offset", fp_edit.l3chksum.offset, argv[index + 1]);
        CTC_CLI_GET_UINT32("mask", fp_edit.l3chksum.mask, argv[index + 2]);

        index = CTC_CLI_GET_SPECIFIC_INDEX("l3chsum-extra-en", index);
        if (0xFF != index)
        {
            fp_edit.l3chksum.extra_update = 1;
        }
    }

    index = CTC_CLI_GET_ARGC_INDEX("l4chsum-update");
    if (0xFF != index)
    {
        fp_edit.l4chksum.enable = 1;
        CTC_CLI_GET_UINT8("offset", fp_edit.l4chksum.offset, argv[index + 1]);
        CTC_CLI_GET_UINT32("mask", fp_edit.l4chksum.mask, argv[index + 2]);

        index = CTC_CLI_GET_SPECIFIC_INDEX("l4chsum-extra-en", index);
        if (0xFF != index)
        {
            fp_edit.l4chksum.extra_update = 1;
        }
    }

    index = CTC_CLI_GET_ARGC_INDEX("is-stage2");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_STAGE2);
    }

    index = CTC_CLI_GET_ARGC_INDEX("keep-l3-len");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_KEEP_L3_LEN);
    }

    index = CTC_CLI_GET_ARGC_INDEX("keep-l4-len");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_KEEP_L4_LEN);
    }

    index = CTC_CLI_GET_ARGC_INDEX("without-template");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_WITHOUT_TMP);
    }

    index = CTC_CLI_GET_ARGC_INDEX("next-fp-id");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT32("next-fp-id", fp_edit.next_fp_id, argv[index + 1]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("rep-sel");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_REP_SEL_VALID);
        CTC_CLI_GET_UINT8("rep select", fp_edit.replace_sel, argv[index + 1]);
    }

    fp_edit.field_cnt = _ctc_cli_fp_field_cnt;
    fp_edit.p_field_list = _ctc_cli_fp_field;

    index = CTC_CLI_GET_ARGC_INDEX("update");
    if (0xFF != index)
    {
        if (g_ctcs_api_en)
        {
            ret = ctcs_nh_update_fp(g_api_ldev, &fp_edit);
        }
        else
        {
            ret = ctc_nh_update_fp(&fp_edit);
        }
    }
    else
    {
        if (g_ctcs_api_en)
        {
            ret = ctcs_nh_add_fp(g_api_ldev, &fp_edit);
        }
        else
        {
            ret = ctc_nh_add_fp(&fp_edit);
        }
    }

    _ctc_cli_fp_field_cnt = 0;
    sal_memset(_ctc_cli_fp_field, 0, sizeof(ctc_nh_fp_field_t)*CTC_NH_FP_FIELD_MAX);

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        goto out;
    }

    if (fp_id == 0)
    {
        ctc_cli_out("fp-id :%d\n", fp_edit.fp_id);
    }
out:
    if (data)
    {
        mem_free(data);
    }

    return ret;

}

CTC_CLI(ctc_cli_usw_nh_remove_fp,
        ctc_cli_usw_nh_remove_fp_cmd,
        "nexthop remove fp-id ID",
        CTC_CLI_NH_M_STR,
        CTC_CLI_NH_DEL_STR,
        "FP id",
        "FP id value"
        )
{
    int32 ret  = CLI_SUCCESS;
    uint32 fp_id = 0;

    CTC_CLI_GET_UINT32("FP ID", fp_id, argv[0]);

    if (g_ctcs_api_en)
    {
        ret = ctcs_nh_remove_fp(g_api_ldev, fp_id);
    }
    else
    {
        ret = ctc_nh_remove_fp(fp_id);
    }

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s \n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;
}

CTC_CLI(ctc_cli_nh_add_misc_fp,
        ctc_cli_nh_add_misc_fp_cmd,
        "nexthop (add|update) misc fp NHID (dsnh-offset OFFSET|alloc-dsnh-offset gchip GCHIP|) (port GPORT_ID|) (fp-id ID) {span-id SPANID|logic-dest-port PORT|bridge-op|reback|mtu-no-check|replace-l2hdr|}",
        CTC_CLI_NH_M_STR,
        CTC_CLI_NH_ADD_STR,
        CTC_CLI_NH_UPDATE_STR,
        CTC_CLI_NH_MISC_STR,
        "Fp",
        CTC_CLI_NH_ID_STR,
        CTC_CLI_NH_DSNH_OFFSET_STR,
        CTC_CLI_NH_DSNH_OFFSET_VALUE_STR,
        CTC_CLI_NH_ALLOC_DSNH_OFFSET_DESC,
        CTC_CLI_GCHIP_DESC,
        CTC_CLI_GCHIP_ID_DESC,
        CTC_CLI_GPORT_DESC,
        CTC_CLI_GPORT_ID_DESC,
        "Fp id",
        "Fp id value",
        "Span id",
        "Value",
        "Logic destination port",
        "Logic port value",
        "Do bridge operation",
        "Reback to source port",
        "MTU no check",
        "Replace layer2 header")
{
    int32 ret  = CLI_SUCCESS;
    uint32 nhid = 0;
    uint8 index = 0;
    ctc_misc_nh_param_t nh_param;
    ctc_misc_nh_fp_edit_param_t fp_edit;
    uint8 alloc_dsnh_gchip = 0;

	ret = _ctc_cli_nh_fp_field_init(vty);
    if (ret == CLI_ERROR)
    {
        ctc_cli_out("%% %s \n", " No memory \n");
        return CTC_E_NO_MEMORY;
    }

    sal_memset(&nh_param, 0, sizeof(ctc_misc_nh_param_t));
    sal_memset(&fp_edit, 0, sizeof(ctc_misc_nh_fp_edit_param_t));

    nh_param.type = CTC_MISC_NH_TYPE_FP_EDIT;

    CTC_CLI_GET_UINT32("Nexthop ID", nhid, argv[1]);
    index = CTC_CLI_GET_ARGC_INDEX("dsnh-offset");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT32("dsnh-offset", nh_param.dsnh_offset, argv[index+1]);
    }
    index = CTC_CLI_GET_ARGC_INDEX("port");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT32("gport", nh_param.gport, argv[index+1]);
    }
    index = CTC_CLI_GET_ARGC_INDEX("fp-id");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT32("fp-id", fp_edit.fp_id, argv[index+1]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("span-id");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT16("span-id", fp_edit.span_id, argv[index+1]);
    }

    index = CTC_CLI_GET_ARGC_INDEX("bridge-op");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_MISC_NH_FP_FLAG_OP_BRIDGE);
    }

    index = CTC_CLI_GET_ARGC_INDEX("reback");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_MISC_NH_FP_FLAG_REBACK);
    }
    index = CTC_CLI_GET_ARGC_INDEX("mtu-no-check");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_MISC_NH_FP_FLAG_MTU_NO_CHK);
    }
    index = CTC_CLI_GET_ARGC_INDEX("replace-l2hdr");
    if (0xFF != index)
    {
        CTC_SET_FLAG(fp_edit.flag, CTC_MISC_NH_FP_FLAG_REPLACE_L2HDR);
    }
    sal_memcpy(&nh_param.misc_param.fp_edit, &fp_edit, sizeof(fp_edit));

    index = CTC_CLI_GET_ARGC_INDEX("logic-dest-port");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT16("logic dest port", nh_param.logic_port, argv[index + 1]);
    }
    index = CTC_CLI_GET_ARGC_INDEX("alloc-dsnh-offset");
    if (0xFF != index)
    {
        CTC_CLI_GET_UINT8("alloc_dsnh_gchip", alloc_dsnh_gchip, argv[index + 2]);
        CTC_ERROR_RETURN(_ctc_nexthop_cli_alloc_dsnh_offset(vty, alloc_dsnh_gchip, CTC_NH_TYPE_MISC, &nh_param));
        return CLI_SUCCESS;
    }

    index = CTC_CLI_GET_ARGC_INDEX("update");
    if (0xFF != index)
    {
        if (g_ctcs_api_en)
        {
            ret = ctcs_nh_update_misc(g_api_ldev, nhid, &nh_param);
        }
        else
        {
            ret = ctc_nh_update_misc(nhid, &nh_param);
        }
    }
    else
    {
        if (g_ctcs_api_en)
        {
            ret = ctcs_nh_add_misc(g_api_ldev, nhid, &nh_param);
        }
        else
        {
            ret = ctc_nh_add_misc(nhid, &nh_param);
        }
    }

    if (ret < 0)
    {
        ctc_cli_out("%% %s \n", ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;
}

int32
ctc_usw_nexthop_fp_cli_init(void)
{
    install_element(CTC_SDK_MODE, &ctc_cli_usw_nh_add_fp_field_cmd);
    install_element(CTC_SDK_MODE, &ctc_cli_usw_nh_add_fp_edit_cmd);
    install_element(CTC_SDK_MODE, &ctc_cli_usw_nh_remove_fp_cmd);
    install_element(CTC_SDK_MODE, &ctc_cli_nh_add_misc_fp_cmd);

    return CLI_SUCCESS;
}

int32
ctc_usw_nexthop_fp_cli_deinit(void)
{
    uninstall_element(CTC_SDK_MODE, &ctc_cli_usw_nh_add_fp_field_cmd);
    uninstall_element(CTC_SDK_MODE, &ctc_cli_usw_nh_add_fp_edit_cmd);
    uninstall_element(CTC_SDK_MODE, &ctc_cli_usw_nh_remove_fp_cmd);
    uninstall_element(CTC_SDK_MODE, &ctc_cli_nh_add_misc_fp_cmd);

    return CLI_SUCCESS;
}

